home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / CD32 / CD32-Tools / cdxl-1 / AudioCDXL.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-27  |  9.7 KB  |  410 lines

  1. /*************
  2.  
  3.     AudioCDXL.c
  4.  
  5.     W.D.L 930330
  6.  
  7. **************/
  8.  
  9. /*
  10.  * COPYRIGHT: Unless otherwise noted, all files are Copyright (c) 1993-1999
  11.  * Amiga, Inc.  All rights reserved.
  12.  *
  13.  * DISCLAIMER: This software is provided "as is".  No representations or
  14.  * warranties are made with respect to the accuracy, reliability, performance,
  15.  * currentness, or operation of this software, and all use is at your own risk.
  16.  * Neither Amiga nor the authors assume any responsibility or liability
  17.  * whatsoever with respect to your use of this software.
  18.  */
  19.  
  20.  
  21. // Tab size is 8!
  22.  
  23. #include <exec/types.h>
  24. #include <graphics/gfxbase.h>
  25.  
  26. #include <devices/audio.h>
  27. #include "devices/cd.h"
  28.  
  29. #include <hardware/custom.h>
  30. #include <hardware/dmabits.h>
  31. #include <hardware/intbits.h>
  32.  
  33. #include <clib/exec_protos.h>
  34. #include <clib/alib_protos.h>
  35.  
  36. #include <pragmas/exec_pragmas.h>
  37.  
  38. #include <string.h>    // for setmem()
  39.  
  40. #include "cdxl/cdxlob.h"
  41. #include "cdxl/runcdxl.h"
  42. #include "cdxl/debugsoff.h"
  43.  
  44. /*    // Uncomment to get debug output turned on
  45. #define KPRINTF
  46. #include "cdxl/debugson.h"
  47. */
  48.  
  49.  
  50. IMPORT struct ExecBase    * SysBase;
  51. IMPORT struct Custom far custom;
  52.  
  53. STATIC UBYTE        * Name0 = "CDXLAUD0";
  54. STATIC struct Interrupt    * Aud0PriorInterrupt;
  55. STATIC struct Interrupt      AUD0Interrupt;
  56. STATIC BOOL          Aud0PriorEnable;
  57. STATIC BOOL          Aud1PriorEnable;
  58. STATIC BOOL          Aud0PriorSet;
  59. STATIC BOOL          Aud1PriorSet;
  60. STATIC BOOL          aud0_installed;
  61.  
  62.  
  63. STATIC struct MsgPort    * AudioPort[4];
  64. STATIC struct IOAudio      IOAudio[4];
  65. STATIC UBYTE          Channels[] = {1,2,4,8};
  66. STATIC BOOL          DeviceOpen[4];
  67.  
  68. STATIC UWORD    Period;        // Global Period
  69.  
  70. IMPORT    CDXLOB * CDXL_OB;    // Global CDXLOB
  71. IMPORT    LONG    XLSignal;
  72. IMPORT    struct Process * parent;
  73.  
  74.  
  75. IMPORT    struct GfxBase    * GfxBase;
  76.  
  77.  
  78. IMPORT    ULONG    Count;
  79. ULONG        SaveCount,AudioCount;
  80. WORD        padjust;
  81.  
  82. IMPORT BOOL    AudioSignalTask;
  83.  
  84. /*
  85.  * The AUD0 interrupt code. This routine gets called immediately after
  86.  * the audio DMA channel has read the location and length registers and
  87.  * stored their values in the back up registers. The philospy here is to
  88.  * rewrite the location registers to point to the other audio buffer in
  89.  * preparation for the next time the audio DMA reads them. It seems that
  90.  * the audio period that was specified is sometimes off by less than 1.
  91.  * For long CDXL files, this will result in the audio getting out of
  92.  * sync with the video. What I do here is add or subtract one from the
  93.  * period to compensate for this. A better way to do this could probably
  94.  * be figured out.
  95.  */
  96. VOID __interrupt __saveds
  97. AUD0Handler( VOID )
  98. {
  99.     // clear AUD0 interrupt
  100.     custom.intreq = INTF_AUD0;
  101.  
  102.     ++AudioCount;
  103.  
  104.     if( !(CDXL_OB->flags & CDXL_DOSXL) ) {
  105.  
  106.     padjust = AudioCount - Count;
  107.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = Period + padjust;
  108.  
  109.     if ( (SaveCount == Count) ) {
  110.         CDXL_OB->curAudio ^= 1;
  111.         AudioCount--;
  112.     } else if ( (Count - SaveCount) > 1) {
  113.         AudioCount++;
  114.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  115.     } else {
  116.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  117.     }
  118.  
  119.     D(PRINTF("%ld-%ld ",CDXL_OB->curAudio,padjust);)
  120.  
  121.     // Point the location registers to the buffer that is currently being filled
  122.     // by the CDXL. If we are timed right, when the CDXL is done reading, the
  123.     // audio DMA should be ready to reread these location registers.
  124.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  125.  
  126.     if ( AudioSignalTask )
  127.         Signal( (struct Task *)parent, XLSignal );
  128.  
  129.     } else {
  130.     // Point the location registers to the buffer that is currently being filled
  131.     // by the CDXL. If we are timed right, when the CDXL is done reading, the
  132.     // audio DMA should be ready to reread these location registers.
  133.     padjust = (AudioCount - Count);
  134.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = Period + padjust;
  135.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  136.  
  137.  
  138.     if ( (SaveCount == Count) ) {
  139.         CDXL_OB->curAudio ^= 1;
  140.         AudioCount--;
  141.     } else if ( (Count - SaveCount) > 1) {
  142.         AudioCount++;
  143.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  144.     } else {
  145.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  146.     }
  147.  
  148. //    custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  149.  
  150.     Signal( (struct Task *)parent, XLSignal );
  151.     }
  152.  
  153.     SaveCount = Count;
  154.  
  155. } // AUD0Handler()
  156.  
  157.  
  158. /*
  159.  * Free the audio channels.
  160.  */
  161. STATIC VOID
  162. FreeAudio( VOID )
  163. {
  164.     int i;
  165.  
  166.     for ( i = 0; i < 4; i++ ) {
  167.     if ( DeviceOpen[i] ) {
  168.         CloseDevice( (struct IORequest *)&IOAudio[i] );
  169.         DeviceOpen[i] = NULL;
  170.         D(PRINTF("Closing channel %ld\n",i);)
  171.     } else {
  172.         D(PRINTF("NOT Closing channel %ld\n",i);)
  173.     }
  174.  
  175.     if ( AudioPort[i] ) {
  176.         DeleteMsgPort( AudioPort[i] );
  177.         AudioPort[i] = NULL;
  178.         D(PRINTF("Deleting Port %ld\n",i);)
  179.     } else {
  180.         D(PRINTF("NOT Deleting Port %ld\n",i);)
  181.     }
  182.     }
  183.  
  184. } // FreeAudio()
  185.  
  186.  
  187. /*
  188.  * Allocate the audio channels. Probably don't need to allocate all 4 but...
  189.  */
  190. STATIC
  191. AllocAudio( VOID )
  192. {
  193.     int    i,ret = RC_OK;
  194.  
  195.     for ( i = 0; i < 4; i++ ) {
  196.     setmem( &IOAudio[i], sizeof ( struct IOAudio ), 0 );
  197.  
  198.     if ( AudioPort[i] = CreateMsgPort() ) {
  199.         IOAudio[i].ioa_Request.io_Message.mn_ReplyPort = AudioPort[i];
  200.         IOAudio[i].ioa_Request.io_Message.mn_Node.ln_Pri = 127;
  201.         IOAudio[i].ioa_AllocKey = 0;
  202.         IOAudio[i].ioa_Data = &Channels[i];
  203.         IOAudio[i].ioa_Length = 1;
  204.         if ( !OpenDevice("audio.device",0,(struct IORequest *)&IOAudio[i],0) ) {
  205.         DeviceOpen[i] = TRUE;
  206.         D(PRINTF("Got channel %ld\n",i);)
  207.         } else {
  208.         DeviceOpen[i] = FALSE;
  209.         D(PRINTF("Did NOT get channel %ld\n",i);)
  210.         ret = RC_NO_AUDIODEVICE;
  211.         break;
  212.         }
  213.     } else {
  214.         ret = RC_NO_MEM;
  215.         break;
  216.     }
  217.     }
  218.  
  219.     if ( ret )
  220.     FreeAudio();
  221.  
  222.     return( ret );
  223.  
  224. } // AllocAudio()
  225.  
  226.  
  227. /*
  228.  * Disable AUD0 & AUD1 DMA as well as the AUD0 interrupt.
  229.  */
  230. VOID
  231. StopAudio( VOID )
  232. {
  233.     // disable AUD0 DMA
  234.     custom.dmacon = DMAF_AUD0;
  235.  
  236.     // disable AUD1 DMA
  237.     custom.dmacon = DMAF_AUD1;
  238.  
  239.     // disable AUD0 interrupt
  240.     custom.intena = INTF_AUD0;
  241.  
  242.     // clear AUD0 interrupt
  243.     custom.intreq = INTF_AUD0;
  244.  
  245. } // StopAudio()
  246.  
  247.  
  248. /*
  249.  * Enable AUD0 & AUD1 DMA as well as the AUD0 interrupt.
  250.  */
  251. VOID
  252. StartAudio( VOID )
  253. {
  254.     // clear AUD0 interrupt
  255.     custom.intreq = INTF_AUD0;
  256.  
  257.     // enable AUD0 DMA
  258.     custom.dmacon = DMAF_SETCLR|DMAF_MASTER|DMAF_AUD0;
  259.  
  260.     // enable AUD1 DMA
  261.     custom.dmacon = DMAF_SETCLR|DMAF_MASTER|DMAF_AUD1;
  262.  
  263.     // enable AUD0 interrupt
  264.     custom.intena = INTF_SETCLR|INTF_AUD0;
  265.  
  266.     AudioCount = 0;
  267.  
  268. } // StartAudio()
  269.  
  270.  
  271. /*
  272.  * Restore the audio system back to how we found it.
  273.  */
  274. VOID
  275. QuitAudio( VOID )
  276. {
  277.     if ( aud0_installed ) {
  278.     aud0_installed = FALSE;
  279.  
  280.     StopAudio();
  281.  
  282.     /*
  283.      * Remove the interrupt we installed and replace it
  284.      * with the old one (if there was one).
  285.      */
  286.     SetIntVector(INTB_AUD0, Aud0PriorInterrupt);
  287.  
  288.     if(Aud0PriorEnable) {
  289.         custom.intena = INTF_SETCLR|INTF_AUD0;
  290.         Aud0PriorEnable = FALSE;
  291.     }
  292.  
  293.     if(Aud1PriorEnable) {
  294.         custom.intena = INTF_SETCLR|INTF_AUD1;
  295.         Aud1PriorEnable = FALSE;
  296.     }
  297.  
  298.     if ( Aud0PriorSet ) {
  299.         custom.intreq = INTF_AUD0;
  300.         Aud0PriorSet = FALSE;
  301.     }
  302.  
  303.     if ( Aud1PriorSet ) {
  304.         custom.intreq = INTF_AUD1;
  305.         Aud1PriorSet = FALSE;
  306.     }
  307.     }
  308.  
  309.     // Free the audio channels we allocated.
  310.     FreeAudio();
  311.  
  312. } // QuitAudio()
  313.  
  314.  
  315. /*
  316.  * Install an AUD0 interrupt
  317.  */
  318. AddAudioInterrupt( VOID )
  319. {
  320.     setmem( &AUD0Interrupt, sizeof ( AUD0Interrupt ), 0 );
  321.  
  322.     /* Initialize the Interrupt node */
  323.     AUD0Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  324.     AUD0Interrupt.is_Node.ln_Pri  = 0;
  325.     AUD0Interrupt.is_Node.ln_Name = Name0;
  326.  
  327.     AUD0Interrupt.is_Data = (APTR)NULL;
  328.     AUD0Interrupt.is_Code = AUD0Handler;
  329.  
  330.     custom.intena = INTF_AUD0|INTF_AUD1;
  331.     custom.intreq = INTF_AUD0|INTF_AUD1;
  332.  
  333.     // Install the new interrupt handler
  334.     Aud0PriorInterrupt = SetIntVector( INTB_AUD0, &AUD0Interrupt );
  335.  
  336.     if (Aud0PriorInterrupt) {
  337.     D(PRINTF("Replaced the %ls AUD0 interrupt handler\n",
  338.         Aud0PriorInterrupt->is_Node.ln_Name);)
  339.     }
  340.  
  341.     return( (int)(aud0_installed = TRUE) );
  342.  
  343. } // AddAudioInterrupt()
  344.  
  345.  
  346. /*
  347.  * Set up the audio system.
  348.  */
  349. InitAudio( CDXLOB * CDXL_ob )
  350. {
  351.     ULONG    freq;
  352.     LONG    rate;
  353.     UWORD    period;
  354.     int        ret;
  355.  
  356.     // If this CDXL has no audio, there is no need.
  357.     if ( !CDXL_ob->AudioSize )
  358.     return( RC_OK );
  359.  
  360.     if ( ret = AllocAudio() )
  361.     return( ret );
  362.  
  363.     // Save state of AUD0 & AUD1 interrupts
  364.     Aud0PriorEnable = custom.intenar & INTF_AUD0 ? TRUE : FALSE;
  365.     Aud1PriorEnable = custom.intenar & INTF_AUD1 ? TRUE : FALSE;
  366.     Aud0PriorSet = custom.intreqr & INTF_AUD0 ? TRUE : FALSE;
  367.     Aud1PriorSet = custom.intreqr & INTF_AUD1 ? TRUE : FALSE;
  368.  
  369.     // Add the Audio interrupt
  370.     AddAudioInterrupt();
  371.  
  372.     // Calculate period
  373.     freq = ( SYSTEM_PAL ? PAL_FREQ : NTSC_FREQ );
  374.  
  375.     D(
  376.      if ( SYSTEM_PAL ) {
  377.     D(PRINTF("SYSTEM_PAL... \n");)
  378.      } else {
  379.     D(PRINTF("SYSTEM_NTSC... \n");)
  380.      }
  381.     )
  382.  
  383.     D(PRINTF("InitAudio() 4.1 freq= %ld, CDXL_ob->AudioSize= %ld, CDXL_ob->FrameSize= %ld\n",
  384.     freq,CDXL_ob->AudioSize,CDXL_ob->FrameSize);)
  385.  
  386.     if ( CDXL_ob->flags & CDXL_DOSXL) {
  387.     rate = INTDIV( (( CDXL_ob->ReadXLSpeed * DEFAULT_SECTOR_SIZE) * CDXL_ob->AudioSize ), CDXL_ob->FrameSize );
  388.     } else {
  389.     rate = INTDIV( ( DATA_TRANS_RATE * CDXL_ob->AudioSize ), CDXL_ob->FrameSize );
  390.     }
  391.  
  392.     period = (UWORD) INTDIV( freq, rate );
  393.  
  394.     D(PRINTF("InitAudio() 4.2 rate= %ld, period= %ld\n",rate,period);)
  395.  
  396.     Period = period;    // Set Global pointer
  397.     padjust = 0;    // Global period adjuster.
  398.  
  399.     CDXL_ob->curAudio = 0;
  400.  
  401.     // Set up the volume,period and length
  402.     custom.aud[ 0 ].ac_vol = custom.aud[ 1 ].ac_vol = CDXL_ob->Volume;
  403.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = period;
  404.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_ob->audio[CDXL_ob->curAudio];
  405.     custom.aud[ 0 ].ac_len = custom.aud[ 1 ].ac_len = ( CDXL_ob->AudioSize / sizeof( UWORD) );
  406.  
  407.     return( RC_OK );
  408.  
  409. } // InitAudio()
  410.